﻿using DimensionsHelper.Common.Utils;
using DimensionsHelper.LanguageService.Protocol;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     源代码文本的行起始位置表。
/// </summary>
public readonly struct SourceTextLineMap
{
    private readonly string _text;
    private readonly List<int> _lineStarts = new();


    public SourceTextLineMap(string text)
    {
        _text = text;
        ComputeLineStarts();
    }


    private void ComputeLineStarts()
    {
        _lineStarts.Clear();
        ReadOnlySpan<char> span = _text.AsSpan();
        int pos = 0;
        int lineStart = 0;

        while (pos < span.Length)
        {
            char ch = span[pos];
            pos++;

            switch (ch)
            {
                case '\n':
                case (char)8232:
                case (char)8233:
                    _lineStarts.Add(lineStart);
                    lineStart = pos;
                    break;
            }
        }

        _lineStarts.Add(lineStart);
    }


    /// <summary>
    ///     计算字符位置对应的行号，0开始。
    /// </summary>
    /// <param name="position">文本位置</param>
    /// <returns>0开始的行号</returns>
    public int ComputeLineOfPosition(int position)
    {
        int line = CollectionHelper.BinarySearch(
            _lineStarts,
            position,
            (lineStart, pos) => lineStart - pos);

        if (line < 0)
        {
            line = ~line - 1;
        }

        return line;
    }


    /// <summary>
    ///     计算指定文本位置的行、列位置。
    /// </summary>
    /// <param name="position">0开始的文本位置</param>
    public Position ComputePosition(int position)
    {
        if (_lineStarts.Count == 0)
        {
            return Position.Create(1, 1);
        }

        int line = ComputeLineOfPosition(position);
        int character = position - _lineStarts[line];
        return Position.Create(line, character);
    }
}